/**
  ******************************************************************************
  * @file    common.c
  * @author  exatron
  * @version V1.0.0
  * @date    segunda, 22 de dezembro de 2014
  * @brief   Source com definições gerais.
  ******************************************************************************
  * @attention
  *
  *
  ******************************************************************************
  */

/**
  * @addtogroup Common
  * @{
  */

/* Includes ------------------------------------------------------------------*/
#include <common.h>

/* Estrutura dos sockets */
extern Socket_t sock[N_SOCKS];

/* FIFO dos ids dos sockets que contem dados */
extern FIFO_t   isrx_fifo;
extern char     isrx_id[N_SOCKS];

/* Variáveies do Select */
Select_t Select;
#ifndef DEBUG_ON_PC
extern int ttyS0_fd;
#endif

/* Contadores de timeout */
int timeout_socket;
static int timeout_conn;
extern int serial0_timeout;
extern int serial1_timeout;

/* Flag de estado da aplicação */
static BooleanType_t Busy;

/* Flags de conf rings */
extern BooleanType_t ISCONNSTATUS;
extern BooleanType_t ISRINGS;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* External functions --------------------------------------------------------*/

void Select_Clear(void)
{
	memset(&Select, 0, sizeof(Select));
	FD_ZERO(&Select.readfds);
}

void Select_Set(void)
{
	int i = 0;

	for(i=0;i<N_SELECT;i++)
	{
		switch(i)
		{
			case Select_usart0:
				#ifdef DEBUG_ON_PC
					FD_SET(STDIN_FILENO , &Select.readfds);
				#else
				if(ttyS0_fd > 0)
					FD_SET(ttyS0_fd , &Select.readfds);
				#endif
				break;
			case Select_TCPServerSocket:
				if(sock[TCP_ServerSocketID].serfd > 0)
					FD_SET(sock[TCP_ServerSocketID].serfd , &Select.readfds);
				break;
			case Select_UDPServerSocket:
				if(sock[UDP_ServerSocketID].serfd > 0)
					FD_SET(sock[UDP_ServerSocketID].serfd , &Select.readfds);
				break;
			case Select_TCPClientSocket:
				if(sock[TCP_ClientSocketID].clifd > 0)
					FD_SET(sock[TCP_ClientSocketID].clifd , &Select.readfds);
				break;
			case Select_UDPClientSocket:
				if(sock[UDP_ClientSocketID].clifd > 0)
					FD_SET(sock[UDP_ClientSocketID].clifd , &Select.readfds);
				break;
			case Select_Sock0:
				if(sock[Sock0].clifd > 0)
					FD_SET(sock[Sock0].clifd , &Select.readfds);
				break;
			case Select_Sock1:
				if(sock[Sock1].clifd > 0)
					FD_SET(sock[Sock1].clifd , &Select.readfds);
				break;
			case Select_Sock2:
				if(sock[Sock2].clifd > 0)
					FD_SET(sock[Sock2].clifd , &Select.readfds);
				break;
			case Select_Sock3:
				if(sock[Sock3].clifd > 0)
					FD_SET(sock[Sock3].clifd , &Select.readfds);
				break;
			case Select_Sock4:
				if(sock[Sock4].clifd > 0)
					FD_SET(sock[Sock4].clifd , &Select.readfds);
				break;
			case Select_Sock5:
				if(sock[Sock5].clifd > 0)
					FD_SET(sock[Sock5].clifd , &Select.readfds);
				break;
			case Select_Sock6:
				if(sock[Sock6].clifd > 0)
					FD_SET(sock[Sock6].clifd , &Select.readfds);
				break;
			case Select_Sock7:
				if(sock[Sock7].clifd > 0)
					FD_SET(sock[Sock7].clifd , &Select.readfds);
				break;
			case Select_Sock8:
				if(sock[Sock8].clifd > 0)
					FD_SET(sock[Sock8].clifd , &Select.readfds);
				break;
			case Select_Sock9:
				if(sock[Sock9].clifd > 0)
					FD_SET(sock[Sock9].clifd , &Select.readfds);
				break;
			case Select_Sock10:
				if(sock[Sock10].clifd > 0)
					FD_SET(sock[Sock10].clifd , &Select.readfds);
				break;
		}
	}
}

int Select_IsSet(SelectID_t SelectID)
{
	switch(SelectID)
	{
		case Select_usart0:
			#ifdef DEBUG_ON_PC
				return FD_ISSET(STDIN_FILENO, &Select.readfds);
			#else
			if(ttyS0_fd > 0)
				return FD_ISSET(ttyS0_fd , &Select.readfds);
			#endif
			break;
		case Select_TCPServerSocket:
			if(sock[TCP_ServerSocketID].serfd > 0)
				return FD_ISSET(sock[TCP_ServerSocketID].serfd , &Select.readfds);
			break;
		case Select_UDPServerSocket:
			if(sock[UDP_ServerSocketID].serfd > 0)
				return FD_ISSET(sock[UDP_ServerSocketID].serfd , &Select.readfds);
			break;
		case Select_TCPClientSocket:
			if(sock[TCP_ClientSocketID].clifd > 0)
				return FD_ISSET(sock[TCP_ClientSocketID].clifd , &Select.readfds);
			break;
		case Select_UDPClientSocket:
			if(sock[UDP_ClientSocketID].clifd > 0)
				return FD_ISSET(sock[UDP_ClientSocketID].clifd , &Select.readfds);
			break;
		case Select_Sock0:
			if(sock[Sock0].clifd > 0)
				return FD_ISSET(sock[Sock0].clifd , &Select.readfds);
			break;
		case Select_Sock1:
			if(sock[Sock1].clifd > 0)
				return FD_ISSET(sock[Sock1].clifd , &Select.readfds);
			break;
		case Select_Sock2:
			if(sock[Sock2].clifd > 0)
				return FD_ISSET(sock[Sock2].clifd , &Select.readfds);
			break;
		case Select_Sock3:
			if(sock[Sock3].clifd > 0)
				return FD_ISSET(sock[Sock3].clifd , &Select.readfds);
			break;
		case Select_Sock4:
			if(sock[Sock4].clifd > 0)
				return FD_ISSET(sock[Sock4].clifd , &Select.readfds);
			break;
		case Select_Sock5:
			if(sock[Sock5].clifd > 0)
				return FD_ISSET(sock[Sock5].clifd , &Select.readfds);
			break;
		case Select_Sock6:
			if(sock[Sock6].clifd > 0)
				return FD_ISSET(sock[Sock6].clifd , &Select.readfds);
			break;
		case Select_Sock7:
			if(sock[Sock7].clifd > 0)
				return FD_ISSET(sock[Sock7].clifd , &Select.readfds);
			break;
		case Select_Sock8:
			if(sock[Sock8].clifd > 0)
				return FD_ISSET(sock[Sock8].clifd , &Select.readfds);
			break;
		case Select_Sock9:
			if(sock[Sock9].clifd > 0)
				return FD_ISSET(sock[Sock9].clifd , &Select.readfds);
			break;
		case Select_Sock10:
			if(sock[Sock10].clifd > 0)
				return FD_ISSET(sock[Sock10].clifd , &Select.readfds);
			break;
	}

	return Result_Error;
}

void Select_Maxfd(void)
{
	int i = 0;

	#ifdef DEBUG_ON_PC
	Select.max_fd = STDIN_FILENO;
	#else
	Select.max_fd = ttyS0_fd;
	#endif

	for(i=0; i<(N_SOCKS); i++)
	{
		if(sock[i].serfd > Select.max_fd)
			Select.max_fd = sock[i].serfd;
		if(sock[i].clifd > Select.max_fd)
			Select.max_fd = sock[i].clifd;
	}

	Select.max_fd += 1;
}

/**
  * @defgroup Common_Functions
  * @{
  */

/**
  * @brief  Função que cria estrutura de pastas.
  * @param  Nenhum
  * @retval Nenhum
  */
void aux_mkdir()
{
	system("if [ ! -d ""/etc/exatron"" ]; then mkdir /etc/exatron; fi");
	system("if [ ! -d ""/etc/exatron/conf"" ]; then mkdir /etc/exatron/conf; fi");
	system("if [ ! -d ""/tmp/exatron"" ]; then mkdir /tmp/exatron; fi");
}

/**
  * @brief  Função que retorna o ID da tarefa a ser executada.
  * @param  char *name: Nome da tarefa a ser executada
  * @retval TaskID_t: ID da tarefa
  */
TaskID_t aux_gettaskid(char *name)
{
	if(strcmp(name, "WF_GRM") == 0)
		return WF_GRM;
	else if(strcmp(name, "WF_GIP") == 0)
		return WF_GIP;
	else if(strcmp(name, "WF_GRIP") == 0)
		return WF_GRIP;
	else if(strcmp(name, "WF_CSAP") == 0)
		return WF_CSAP;
	else if(strcmp(name, "WF_CIK") == 0)
		return WF_CIK;
	else if(strcmp(name, "WF_CST") == 0)
		return WF_CST;
	else if(strcmp(name, "WF_DCN") == 0)
		return WF_DCN;
	else if(strcmp(name, "WF_SCAN") == 0)
		return WF_SCAN;
	else if(strcmp(name, "WF_ISD") == 0)
		return WF_ISD;
	else if(strcmp(name, "WF_SRT") == 0)
		return WF_SRT;
	else if(strcmp(name, "WF_PIP") == 0)
		return WF_PIP;
	else if(strcmp(name, "WF_IPOK") == 0)
		return WF_IPOK;
	else if(strcmp(name, "SCK_IRDR") == 0)
		return SCK_IRDR;
	else if(strcmp(name, "SCK_IRDR2") == 0)
		return SCK_IRDR2;
	else if(strcmp(name, "SCK_RXD") == 0)
		return SCK_RXD;
	else if(strcmp(name, "SCK_ITDR") == 0)
		return SCK_ITDR;
	else if(strcmp(name, "SCK_TXD") == 0)
		return SCK_TXD;
	else if(strcmp(name, "SCK_GSS") == 0)
		return SCK_GSS;
	else if(strcmp(name, "SCK_CLOS") == 0)
		return SCK_CLOS;
	else if(strcmp(name, "TCP_CNC") == 0)
		return TCP_CNC;
	else if(strcmp(name, "TCP_OPS") == 0)
		return TCP_OPS;
	else if(strcmp(name, "UDP_OPC") == 0)
		return UDP_OPC;
	else if(strcmp(name, "UDP_OPS") == 0)
		return UDP_OPS;
	else if(strcmp(name, "CFG_SNP") == 0)
		return CFG_SNP;
	else if(strcmp(name, "CFG_GNP") == 0)
		return CFG_GNP;
	else if(strcmp(name, "CFG_STOS") == 0)
		return CFG_STOS;
	else if(strcmp(name, "CFG_GTOS") == 0)
		return CFG_GTOS;
	else if(strcmp(name, "CFG_STOU") == 0)
		return CFG_STOU;
	else if(strcmp(name, "CFG_GTOU") == 0)
		return CFG_GTOU;
	else if(strcmp(name, "CFG_SBR") == 0)
		return CFG_SBR;
	else if(strcmp(name, "CFG_GBR") == 0)
		return CFG_GBR;
	else if(strcmp(name, "SW_R") == 0)
		return SW_R;
	else if(strcmp(name, "SW_GV") == 0)
		return SW_GV;
	else if(strcmp(name, "SW_CB") == 0)
		return SW_CB;
	else if(strcmp(name, "SW_EXEC") == 0)
		return SW_EXEC;
	else if(strcmp(name, "SW_CSC") == 0)
		return SW_CSC;
	else if(strcmp(name, "SW_RGC") == 0)
		return SW_RGC;
	return Result_Error;
}

/**
  * @brief  Função que convert int em string.
  * @param  int num: Número a converter
  * @retval char *: String do número
  */
char *aux_itoa(int num)
{
	static char aux_itoa_buf[50];

	bzero(aux_itoa_buf, sizeof(aux_itoa_buf));
	sprintf(aux_itoa_buf,"%d",num);

	return aux_itoa_buf;
}

/**
  * @brief  Elimina o caracter c da string s.
  * @param  char *s: String a eliminar c
  * @param  char c: Caracter a eliminar
  * @param  int len: Tamanho do vetor s
  * @retval Nenhum
  */
void aux_removec(char *s, char c, int len)
{
	int size = 0;
	int offset = 0;
	int i = 0;
	char ctemp;

	size = strlen(s);

	for(i=0;i<size;i++)
	{
		ctemp = s[i];

		if(ctemp != c)
		{
			((char *)s)[offset] = ctemp;
			offset++;
		}
	}
	bzero(s+offset,len-offset);
}

/**
  * @brief  Conta a ocorrência de um caracter.
  * @param  char *s: String a fazer a contagem
  * @retval char c: Caracter a fazer a contagem
  */
int strcntc(char *s, char c)
{
	int i=0, len=0, n=0;
	len = strlen(s);
	for(i=0;i<len;i++)
	{
		if(s[i] == c)
			n++;
	}

	return n;
}

/**
  * @brief  Escreve uma linha no arquivo.
  * @param  char *path: Caminho para o arquivo
  * @param  char *filename: Nome do arquivo
  * @param  char *msg: Texto a escrever no arquivo
  * @param  char *errormsg: Menssagem de erro em caso de falha
  * @retval Nenhum
  */
void aux_FileWrLine(char *path, char *filename, char *msg, char *errormsg)
{
	char temp_buf[255];
	FILE *fp;

	bzero(temp_buf, sizeof(temp_buf));
	sprintf(temp_buf,"%s%s",path,filename);
	fp = fopen(temp_buf,"w");
	if(!fp)
	{
		return;
	}else
	{
		fputs(msg,fp);
		fclose(fp);
	}
}

/**
  * @brief  Lê uma linha do arquivo.
  * @param  char *path: Caminho para o arquivo
  * @param  char *filename: Nome do arquivo
  * @param  char *errormsg: Menssagem de erro em caso de falha
  * @retval char *: Texto lido
  */
char *aux_FileRdLine(char *path, char *filename, char *errormsg)
{
	static char buf_read[1024];
	char temp_buf[255];
	FILE *fp;

	bzero(temp_buf, sizeof(temp_buf));
	bzero(buf_read, sizeof(buf_read));
	sprintf(temp_buf,"%s%s",path,filename);
	fp = fopen(temp_buf,"r");
	if(!fp)
	{
		return aux_itoa(Result_Error);
	}else
	{
		fgets(buf_read, sizeof(buf_read), fp);
		aux_removec(buf_read, '\n', sizeof(buf_read));
		fclose(fp);
	}

	return buf_read;
}

/**
  * @brief  Limpa todos os arquivos flag.
  * @param  Nenhum
  * @retval Nenhum
  */
void aux_ClearFlags()
{
	int i=0;

	/* Limpa estruturas de socket */
	for(i=0;i<(N_SOCKS);i++)
	{
		aux_ClearSocket(i);
	}

	/* Init da FIFO de dados disponiveis Rx */
	fifo_init(&isrx_fifo, isrx_id, sizeof(isrx_id), FIFO_CHAR);

	/* Se não estiver em AP seta para conectando */
	if(aux_GetConnectionState() != Status_SoftAP)
		aux_SetConnectionState(Status_ConnectionConnecting);

	/* Cria arquivos temporários */
	aux_FileWrLine(PATH_TEMP, "gateway", aux_itoa(Result_Error), "Error aux_ClearFlags\r\n");
	aux_FileWrLine(PATH_TEMP, "ispingok", aux_itoa(Result_Error), "Error aux_ClearFlags\r\n");
	aux_FileWrLine(PATH_TEMP, "pingresult", aux_itoa(Result_Error), "Error aux_ClearFlags\r\n");
	aux_FileWrLine(PATH_TEMP, "scandone", aux_itoa(Result_Error), "Error aux_ClearFlags\r\n");
	aux_FileWrLine(PATH_TEMP, "scanresult", aux_itoa(Result_Error), "Error aux_ClearFlags\r\n");
	aux_FileWrLine(PATH_TEMP, "scantemp", aux_itoa(Result_Error), "Error aux_ClearFlags\r\n");

	/* Seta timeout se ainda não existir */
	if(aux_CFG_GetTimeOutSocket() == Result_Error)
		aux_CFG_SetTimeOutSocket(10);

	/* Seta timeout se ainda não existir */
	if(aux_CFG_GetTimeOutUSART() == Result_Error)
		aux_CFG_SetTimeOutUSART(10);

	/* Inicializa timeout */
	timeout_socket = aux_CFG_GetTimeOutSocket();
	timeout_conn = 30;

	/* Seta baudrate se ainda não existir */
	if(aux_CFG_GetBaudRate(SERIAL_CONTROL) == Result_Error)
		aux_CFG_SetBaudRate(SERIAL_CONTROL, 57600);

	/* Seta baudrate se ainda não existir */
	if(aux_CFG_GetBaudRate(SERIAL_DATA) == Result_Error)
		aux_CFG_SetBaudRate(SERIAL_DATA, 57600);

	/* Seta conf da conexão se ainda não existir */
	if(atoi(aux_FileRdLine(PATH_CONF, "connstatusconf", "ConnStatusRead\r\n")) == Result_Error)
		aux_FileWrLine(PATH_CONF, "connstatusconf", aux_itoa(TRUE), "ConnStatusConf\r\n");

	/* Seta conf do status de conexão */
	ISCONNSTATUS = atoi(aux_FileRdLine(PATH_CONF, "connstatusconf", "ConnStatusRead\r\n"));

	/* Seta conf dos rings se ainda não existir */
	if(atoi(aux_FileRdLine(PATH_CONF, "ringconf", "RingRead\r\n")) == Result_Error)
		aux_FileWrLine(PATH_CONF, "ringconf", aux_itoa(FALSE), "RingConf\r\n");

	/* Seta conf dos rings */
	ISRINGS = atoi(aux_FileRdLine(PATH_CONF, "ringconf", "RingRead\r\n"));

	/* Seta estado busy para FALSE */
	aux_SetBusy(FALSE);
}

/**
  * @brief  Seta estado busy.
  * @param  BooleanType_t opt: Estado
  * @retval Nenhum
  */
void aux_SetBusy(BooleanType_t opt)
{
	Busy = opt;
}

/**
  * @brief  Lê estado busy.
  * @param  Nenhum
  * @retval BooleanType_t: Estado
  */
BooleanType_t aux_GetBusy()
{
	return Busy;
}

/**
  * @brief  Verifica se uma string representa um
  * 		inteiro sem sinal.
  * @param  char *s: String a verificar
  * @retval BooleanType_t: Verdadeiro ou falso
  */
BooleanType_t aux_IsNumber(char *s)
{
	#ifdef DEBUG
	debug_append("%s - %s", __FUNCTION__, "enter");
	#endif

	int i;

	if(strlen(s) == 0) return FALSE;

	for(i=0;i<strlen(s);i++)
	{
		if(s[i] < '0' || s[i] > '9')
			return FALSE;
	}

	#ifdef DEBUG
	debug_append("%s - %s", __FUNCTION__, "exit");
	#endif

	return TRUE;
}

/**
  * @}
  */

/**
  * @defgroup SCK_Functions
  * @{
  */

/**
  * @brief  Zera a estrutura do socket.
  * @param  SocketID_t: Socket a zerar
  * @retval Nenhum
  */
void aux_ClearSocket(SocketID_t id)
{
	char isrx_buf[N_SOCKS];
	int nr=0, i=0, temp_id=0;

	memset(&sock[id], 0, sizeof(sock[id]));
	sock[id].isrx = NoRead;
	sock[id].istx = NoWrite;
	sock[id].status = Status_SocketClosed;

	/* Init da FIFO dos dados recebidos */
	fifo_init(&sock[id].fifo_rx, sock[id].Data.buf_rx, RX_BUF_LEN, FIFO_CHAR);

	/* Limpa Rx da FIFO */
	nr = fifo_read(&isrx_fifo, isrx_buf, N_SOCKS);
	for(i=0; i<nr; i++)
	{
		temp_id = isrx_buf[i];
		if(temp_id != id)
			fifo_write(&isrx_fifo, &temp_id, 1);
	}
}

/**
  * @brief  Fecha um socket.
  * @param  SocketID_t: Socket a fechar
  * @retval Nenhum
  */
Result_t aux_CloseSocket(SocketID_t id)
{
	#ifdef DEBUG
	debug_append(__FUNCTION__);
	#endif

	int i = 0;

	/* Verifica se o socket esta aberto */
	if(sock[id].status == Status_SocketClosed)
	{
	   	return Result_SocketClosed;
	}
	else
	{
		/* Se Clients do TCP_Server ou TCP_Client ou UDP_Client ou UDP_Server */
		if(id > 0)
		{
			if(sock[id].clifd > 0)
				shutdown(sock[id].clifd, 2);
			if(sock[id].serfd > 0)
				shutdown(sock[id].serfd, 2);
		}

		/* Se TCP_Server */
		if(id == TCP_ServerSocketID)
		{
			/* Fecha o server e limpa */
			if(sock[id].serfd > 0)
				close(sock[id].serfd);
			aux_ClearSocket(id);

			/* Fecha os clients, eles se fecham */
			for(i=Sock0;i<(N_BACKLOG+Sock0);i++)
			{
				if(sock[i].clifd > 0)
					shutdown(sock[i].clifd, 2);
			}
		}
	}

	return Result_Ok;
}

/**
  * @brief  Envia sinais de mudança de estado dos sockets.
  * @param  "Formato", argumentos
  * @retval Nenhum
  */
void aux_SendSignal(const char *format, ...)
{
	va_list args;
	char buf[255];

	bzero(buf, sizeof(buf));

	va_start(args, format);
	vsprintf(buf, format, args);
	va_end(args);

	aux_USART0_puts(buf);
}

BooleanType_t SCK_CheckID(char *id)
{
	/* Verifica consistência do id */
	if(aux_IsNumber(id) != TRUE)
		return FALSE;
	else if((atoi(id) > (N_SOCKS-1)) || (atoi(id) < 0))
		return FALSE;

	return TRUE;
}

/**
  * @}
  */

/**
  * @brief  Monitora timeout dos sockets.
  * @param  Recebe sinal origem de disparo
  * @retval Nenhum
  */
void aux_back_functions(int sig)
{
	int i=0;

	static ConnectionStatus_t status = Status_ConnectionDisconnected;
	ConnectionStatus_t temp;

	static int cont_conn = 0;
	static int offset = 0;

	alarm(0);

	/* Serial timeout */
	serial0_timeout++;
	serial1_timeout++;

	/* Se timeout_socket */
	for(i=2;i<(N_SOCKS);i++)
	{
		if((sock[i].istimeout < timeout_socket) && (sock[i].status != Status_SocketClosed))
		{
			sock[i].istimeout++;
		}
		else if(sock[i].status != Status_SocketClosed)
		{
			aux_CloseSocket(i);
		}
	} /* Se timeout_socket */

	if(offset == 60)
	{
		/* Se timeout_conn */
		if(cont_conn >= timeout_conn)
		{
			if(aux_GetConnectionState() == Status_ConnectionConnecting)
			{
				/* Se não pegou IP ainda conectando */
				if(aux_WF_GetIP() != Result_Ok)
				{
					temp = Status_ConnectionConnecting;
				}
				/* Se ja pegou IP */
				else
				{
					temp = Status_ConnectionConnected;
				}
			}
			else if(aux_GetConnectionState() == Status_SoftAP)
			{
				temp = Status_SoftAP;
			}
			else if(aux_WF_GetIP() != Result_Ok)
			{
				temp = Status_ConnectionDisconnected;
			}
			else
			{
				temp = Status_ConnectionConnected;
			}

			if(temp != status)
			{
				status = temp;
				aux_SetConnectionState(status);
				if(ISCONNSTATUS == TRUE)
				{
					aux_USART0_puts("%s=%d\r\n", "WF_CST", status);
				}
			}
			cont_conn = 0;
		}
		else
		{
			cont_conn++;
		} /* Se timeout_conn */
	}
	else
	{
		offset++;
	}

	alarm(1);
}

/**
  * @defgroup CFG_Functions
  * @{
  */

/**
  * @brief  Seta timeout p/ sockets.
  * @param  int timeout
  * @retval Nenhum
  */
void aux_CFG_SetTimeOutSocket(int timeout)
{
	aux_FileWrLine(PATH_CONF, "sockettimeout", aux_itoa(timeout), "Erro SetTimeOutSocket\r\n");
}

/**
  * @brief  Seta timeout p/ serial.
  * @param  int timeout
  * @retval Nenhum
  */
void aux_CFG_SetTimeOutUSART(int timeout)
{
	aux_FileWrLine(PATH_CONF, "usarttimeout", aux_itoa(timeout), "Erro SetTimeOutUSART\r\n");
}

/**
  * @brief  Lê timeout p/ sockets.
  * @param  Nenhum
  * @retval int timeout
  */
int aux_CFG_GetTimeOutSocket(void)
{
	return atoi(aux_FileRdLine(PATH_CONF, "sockettimeout", "Erro GetTimeOutSocket\r\n"));
}

/**
  * @brief  Lê timeout p/ serial.
  * @param  Nenhum
  * @retval int timeout
  */
int aux_CFG_GetTimeOutUSART(void)
{
	return atoi(aux_FileRdLine(PATH_CONF, "usarttimeout", "Erro GetTimeOutUSART\r\n"));
}

/**
  * @brief  Seta timeout do socket, passa a ter efeito
  * 		no próximo reboot.
  * @param  SerialType_t serial: Serial a setar
  * @param  int baudrate: baudrate a setar
  * @retval Result_t: Se bem sucedido ou não
  */
Result_t aux_CFG_SetBaudRate(SerialType_t serial,int baudrate)
{
	char temp_buf[50];

	bzero(temp_buf, sizeof(temp_buf));

	switch(baudrate)
	{
		case 9600:
			sprintf(temp_buf, "%d", B9600);
			break;
		case 19200:
			sprintf(temp_buf, "%d", B19200);
			break;
		case 38400:
			sprintf(temp_buf, "%d", B38400);
			break;
		case 57600:
			sprintf(temp_buf, "%d", B57600);
			break;
		case 115200:
			sprintf(temp_buf, "%d", B115200);
			break;
		case 230400:
			sprintf(temp_buf, "%d", B230400);
			break;
		case 460800:
			sprintf(temp_buf, "%d", B460800);
			break;
		default:
			return Result_Error;
	}

	if(serial == SERIAL_CONTROL)
		aux_FileWrLine(PATH_CONF, "baudcontrol", temp_buf, "Erro baud\r\n");
	else if(serial == SERIAL_DATA)
		aux_FileWrLine(PATH_CONF, "bauddata", temp_buf, "Erro baud\r\n");
	else
	{
		return Result_Error;
	}

	return Result_Ok;
}

/**
  * @brief  Get timeout do socket.
  * @param  SerialType_t serial: Serial a verificar
  * @retval int: Baudrate
  */
int aux_CFG_GetBaudRate(SerialType_t serial)
{
	if(serial == SERIAL_CONTROL)
		return atoi(aux_FileRdLine(PATH_CONF, "baudcontrol", "Erro baud\r\n"));
	else if(serial == SERIAL_DATA)
		return atoi(aux_FileRdLine(PATH_CONF, "bauddata", "Erro baud\r\n"));

	return Result_Error;
}

/**
  * @}
  */

/**
  * @defgroup WF_Functions
  * @{
  */

/**
  * @brief  Função retorna se ping foi bem sucedido.
  * @param  char *ip: IP ou DNS a pingar
  * @retval Result_t: Resultado do ping
  */
Result_t aux_WF_PingIP(char *ip)
{
	char line[255], cmd[255], file[255];
	FILE *fp;

	bzero(line, sizeof(line));
	bzero(cmd, sizeof(cmd));
	bzero(file, sizeof(file));

	/* Copia o comando para cmd */
	sprintf(cmd,"%s%s%s","ping -c1 ",ip," 2> /dev/null | grep received | awk '{print $4}' > ");

	/* Copia o caminho para file */
	sprintf(file,"%s%s",PATH_TEMP,"pingresult");

	/* Adiciona o arquivo ao comando */
	strcat(cmd, file);

	/* Executa o comando e salva o conteúdo no arquivo */
	system(cmd);

	/* Abre o arquivo */
	fp = fopen(file, "r");

	/* Lê a única linha */
	fscanf(fp,"%s",line);
	fclose(fp);

	/* Copia o caminho para file */
	bzero(file, sizeof(file));
	sprintf(file,"%s%s",PATH_TEMP,"ispingok");

	/* Abre o arquivo */
	fp = fopen(file, "w");

	if(strcmp(line,"1") == 0)
	{
		fprintf(fp,"%d",Result_Ok);
		fclose(fp);
		return Result_Ok;
	}
	else
	{
		fprintf(fp,"%d",Result_Error);
		fclose(fp);
		return Result_Error;
	}
	return Result_Error;
}

/**
  * @brief  Função retorna se conseguiu determinar ip do router.
  * @param  Nenhum
  * @retval Result_t
  */
Result_t aux_WF_GetRouterIP(void)
{
	if(strlen(aux_WF_GetCharRouterIP()) > 1)
		return Result_Ok;

	return Result_Error;
}

/**
  * @brief  Função retorna IP do router.
  * @param  Nenhum
  * @retval char *: IP do router
  */
char *aux_WF_GetCharRouterIP(void)
{
	static char line[255];
	char cmd[255], file[255];

	bzero(cmd,sizeof(cmd));
	bzero(file,sizeof(file));
	bzero(line,sizeof(line));

	sprintf(file,"%s%s",PATH_TEMP,"gateway");
	sprintf(cmd,"%s%s","netstat -rn 2> /dev/null | grep '^0\\.0\\.0\\.0' | awk '{print $2}' > ",file);

	/* Executa o comando e salva o conteúdo no arquivo */
	system(cmd);

	strcpy(line,aux_FileRdLine(PATH_TEMP,"gateway","Erro lendo IP\r\n"));

    return line;
}

/**
  * @brief  Função retorna se conseguiu determinar IP.
  * @param  Nenhum
  * @retval Result_t: Resultado do GetIP
  */
Result_t aux_WF_GetIP(void)
{
	if(strlen(aux_WF_GetCharIP()) > 1)
		return Result_Ok;

	return Result_Error;
}

/**
  * @brief  Função retorna IP do rádio.
  * @param  Nenhum
  * @retval Result_t: IP
  */
char *aux_WF_GetCharIP(void)
{
    int dSocket;                                /*!< Socket para manipulação de ioctl */
    struct ifreq xIRS;                  /*!< Interface request structure */
    #ifdef DEBUG_ON_PC
    char *iface = "eth0";               /*!< Nome da interface */
    #else
    char *iface = "wlan0";              /*!< Nome da interface */
    #endif
    struct sockaddr_in *xIP;    /*!< Internet socket address */

    static char ip[100];

    bzero(ip, sizeof(ip));

    /* Zera a estrutura xIRS */
    memset(&xIRS, 0, sizeof(xIRS));

    /* Zera a estrutura xIP */
    memset(&xIP, 0, sizeof(xIP));

    /* Cria socket, família AF_INET, tipo sequencial */
    dSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(dSocket != -1) // Socket Ok
    {
        /* Informa a família ao xIRS */
        xIRS.ifr_addr.sa_family = AF_INET;

        /* Copia nome da interface para a estrutura xIRS */
        strcpy(xIRS.ifr_name, iface);

        /* Faz a requisição do comando SIOCGIFADDR ao I/O
         * dSocket
         */
        if (ioctl(dSocket, SIOCGIFADDR, &xIRS) != -1) // ioctl Ok
        {
                xIP = (struct sockaddr_in*)&xIRS.ifr_addr;
                strcpy(ip, inet_ntoa(xIP->sin_addr));
                return ip;
        }
        else // ioctl error
        {
                return aux_itoa(Result_IoctlError);
        }
        close(dSocket);
    }
    else // Socket error
    {
        return aux_itoa(Result_OnOpen);
    }

    return aux_itoa(Result_Error);
}

/**
  * @brief  Escreve o estado da conexão.
  * @param  ConnectionStatus_t ConnectionStatus: Estado da conexão
  * @retval Nenhum
  */
void aux_SetConnectionState(ConnectionStatus_t ConnectionStatus)
{
	aux_FileWrLine(PATH_CONF, "connectionstate", aux_itoa(ConnectionStatus), "Error aux_SetConnectionState\r\n");
}

/**
  * @brief  Retorna o estado de conexão.
  * @param  Nenhum
  * @retval ConnectionStatus_t: Estado da conexão
  */
ConnectionStatus_t aux_GetConnectionState(void)
{
	return atoi(aux_FileRdLine(PATH_CONF, "connectionstate", "Error aux_GetConnectionState\r\n"));
}

/**
  * @}
  */

/**
  * @defgroup FIFO_Functions
  * @{
  */

/**
 * @brief  Inicializa a estrutura da FIFO.
 * @param  FIFO_t: Ponteiro para a estrutura FIFO
 * @param  buf: Ponteiro para o buffer da FIFO
 * @param  size: Tamanho da FIFO
 * @retval Nenhum
 */
void fifo_init(FIFO_t *f, void *buf, int size, FIFOType_t type)
{
	f->head = 0;
    f->tail = 0;
    f->size = size;
    f->type = type;
    f->buf = buf;
}

/**
 * @brief  Verifica se a FIFO está vazia.
 * @param  FIFO_t: Ponteiro para a estrutura FIFO
 * @retval FifoStatus_t: Retorna FifoStatus_t
 */
FIFOStatus_t fifo_isempty(FIFO_t *f)
{
	if(f->head == f->tail)
		return FIFO_ISEMPTY;
	else
		return FIFO_NOEMPTY;
}

/**
 * @brief  Lê da FIFO.
 * @param  FIFO_t: Ponteiro para a estrutura FIFO
 * @param  buf: Ponteiro para o buffer que irá contem
 * 				os dados lidos
 * @param  nbytes: Número de dados a lêr
 * @retval int: Número de dados lidos
 */
int fifo_read(FIFO_t *f, void *buf, int n)
{
	int i;
    int *pint;
    char *pchar;

    pint = buf;
    pchar = buf;

    for(i=0; i < n; i++)
    {
    	/* Verifica se não está vazio */
    	if( f->tail != f->head )
    	{
    		if(f->type == FIFO_INT)
    		{
    			*pint++ = ((int *)f->buf)[f->tail];
    		}
    		if(f->type == FIFO_CHAR)
    		{
    			*pchar++ = ((char *)f->buf)[f->tail];
    		}
			f->tail++;
            if( f->tail == f->size )
            {
            	f->tail = 0;
            }
        }
    	else
    		return i;
    }

    return n;
}

/**
 * @brief  Escreve na FIFO.
 * @param  FIFO_t: Ponteiro para a estrutura FIFO
 * @param  buf: Ponteiro para o buffer que contem
 * 				os dados a serem escritos
 * @param  nbytes: Número de dados a escrever
 * @retval int: Número de dados escritos
 */
int fifo_write(FIFO_t *f, const void *buf, int n)
{
	int i;
    const int *pint;
    const char *pchar;

    pint = buf;
    pchar = buf;

    for(i=0; i < n; i++)
    {
    	/* Verifica se não está cheio */
        if( (f->head + 1 == f->tail) || ( (f->head + 1 == f->size) && (f->tail == 0) ))
        	return i; //no more room
        else
        {
        	if(f->type == FIFO_INT)
        	{
        		((int *)f->buf)[f->head] = *pint++;
        	}
        	if(f->type == FIFO_CHAR)
        	{
        		((char *)f->buf)[f->head] = *pchar++;
        	}
        	f->head++;
            if(f->head == f->size)
            {
            	f->head = 0;
            }
        }
    }

    return n;
}

/**
  * @}
  */

/**
  * @}
  */










